/* eslint-env node, es6 */
/* eslint angular/json-functions:0 */

'use strict';

const gulp = require('gulp');
const path = require('path');
const $ = require('gulp-load-plugins')(); // load all gulp-* modules
const through2 = require('through2');

// load configuration files
const conf = require('./conf.js');

exports.tasks = { injectMaterial: injectMaterial };

function injectMaterial() {
	var mdPaths = [];

	for (var i=0; i < conf.material.modules.length; i++) {
		mdPaths.push(path.join(conf.material.basePath, conf.material.modules[i],
							   conf.material.modules[i] + '.js'));
		mdPaths.push(path.join(conf.material.basePath, conf.material.modules[i],
							   conf.material.modules[i] + '.css'));
	}

	const mdModules = gulp.src(mdPaths, { allowEmpty: true })
	                      .pipe(buildNgMaterialDefinition())
	                      .pipe($.debug());
	mdModules.pipe($.if(/ngMaterial/, gulp.dest('.')));

	return gulp.src(path.join(conf.path.mainHtml('tmp', '')))
		.pipe($.inject(mdModules, { name: 'material', relative:  true }))
		.pipe(gulp.dest(conf.paths.tmp));
}


// *** functions adapted form Angular Material's gulp files ***


function buildNgMaterialDefinition() {
	var srcBuffer = [];
	var modulesSeen = [];

	return through2.obj(function(file, enc, next) {
		var module = findModule.material(file.contents);
		if (module) modulesSeen.push(module.name);
		srcBuffer.push(file);
		next();
	}, function Flush(done) {
		var self = this;
		var requiredLibs = ['ng', 'ngAnimate', 'ngAria'];
		var dependencies = JSON.stringify(requiredLibs.concat(modulesSeen));
		var ngMaterialModule = conf.closure.pre +
		                       'angular.module(\'ngMaterial\', ' + dependencies + ');\n' +
		                       conf.closure.post;

		var angularFile = new $.util.File({
			path:  path.join(process.cwd(), conf.paths.tmp, '/ngMaterial.js'),
			contents: new Buffer(ngMaterialModule)
		});

    // Elevate ngMaterial module registration to first in queue
		self.push(angularFile);

		srcBuffer.forEach(function(file) {
			self.push(file);
		});

		srcBuffer = [];
		done();
	});
}


/**
 * The Angular Material module `ngMaterial` is generated by scanning all Material components
 * for valid module definitions. @see gulp-utils.js  ::buildNgMaterialDefinition()
 *
 * angular.module('ngMaterial', [
 *    "ng","ngAnimate","ngAria",
 *    "material.core","material.core.gestures","material.core.layout","material.core.theming.palette",
 *    ...
 *  ]);
 *
 */

// Define patterns for AngularJS Module definitions

var MATERIAL_ONLY = /\.module\(['|"](material\.[a-zA-Z\-\.]*)['|"]\s*,(\s*\[([^\]]*)\])/;
var ANY = /\.module\(('[^']*'|"[^"]*")\s*,(?:\s*\[([^\]]+)\])?/;

const findModule = {
	material : buildScanner( MATERIAL_ONLY ),
	any      : buildScanner( ANY )
};


/*
 * Find module definition s that match the module definition pattern
 */
function buildScanner(pattern) {
	return function findPatternIn(content) {
		var dependencies;
		var match = pattern.exec(content || '');
		var moduleName = match ? match[1].replace(/\'/gi, '') : null;
		var depsMatch = match && match[2] && match[2].trim();

		if (depsMatch) {
			dependencies = depsMatch.split(/\s*,\s*/).map(function(dep) {
				dep = dep.trim().slice(1, -1); // remove quotes
				return dep;
			});
		}

		return match ? {
			name         : moduleName || '',
			module       : moduleName || '',
			dependencies : dependencies || []
		} : null;
	};
}

